// 云函数入口文件
const cloud = require('wx-server-sdk')

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
}) // 使用当前云环境

const db = cloud.database()
const _ = db.command

// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  const {
    cmd,
    userOpenId,
    userRole
  } = event
  if (userOpenId == true) event.userOpenId = wxContext.OPENID

  if (cmd == 'putMsg') {
    return await putMsg(event) // { chatId, content }
  } else if (cmd == 'getMsg') {
    return await getMsg(event)
  } else if (cmd == 'peekNewMsg') {
    return await peekNewMsg(event) // { userId | userOpenId, userRole: undefined | 'roleName' }
  }
  return {}
}

async function putMsg(data) {
  const {
    chatId,
    content,
  } = data
  return await db.collection('chat')
    .where({
      _id: chatId
    })
    .update({
      data: {
        contents: _.push({
          ...content,
        })
      }
    })
}

async function getMsg(data) { // not used
  const {
    contentLength,
    retrieveLength,
    latestTime,
    sessionOpenId
  } = data
  const _ = db.command,
    $ = _.aggregate,
    source = data.source || 'refresher'

  let projectObj = {}
  if (source == 'refresher') {
    projectObj = {
      _id: 1,
      _openid: 1,
      contents: contentLength == 0 ? $.slice(['$contents', -retrieveLength]) : $.slice(['$contents', -(contentLength + retrieveLength), retrieveLength]),
    }
  } else {
    projectObj = {
      _id: 1,
      _openid: 1,
      contents: latestTime ? ($.filter({
        input: '$contents',
        as: 'item',
        cond: $.gt(['$$item.time', latestTime])
      })) : 1
    }
  }
  return db.collection('chat')
    .aggregate()
    .match({
      sessionOpenId: _.eq(sessionOpenId)
    })
    .project(projectObj)
    .end()
}

function sessionOpenIdOrUserIdCondi(userId, userOpenId) {
  const condi = {}
  if (userId) condi.userId = _.eq(userId)
  else if (userOpenId) condi.sessionOpenId = _.eq(userOpenId)
  return condi
}

async function peekNewMsg(event) {
  const {
    userId,
    userOpenId,
    userRole
  } = event
  const userRes = await db.collection('users')
    .where({
      _id: userId ? _.eq(userId) : _.exists(true),
      _openid: userOpenId ? _.eq(userOpenId) : _.exists(true)
    })
    .get();
  const user = userRes.data[0]

  if (!userRole) event.userRole = user.role
  const chatRes = await db.collection('chat')
    .where(await buildChatCondition(event)) // userRole
    .get()
  let totalNewMsgCount = 0,
    chatList = []
  for (const chat of chatRes.data) {
    const count = getNewMsgCount(chat, user)
    if (count <= 0) continue
    totalNewMsgCount += count
    chatList.push({
      _id: chat._id,
      sessionOpenId: chat.sessionOpenId,
      userId: chat.userId,
      newMsgCount: count
    })
  }
  return {
    totalNewMsgCount,
    chatList
  }
}

async function buildChatCondition(event) {
  const {
    userId,
    userRole,
    userOpenId
  } = event

  const hasContents = {
    contents: _.elemMatch({
      time: _.exists(true)
    })
  }

  if (userRole == 'admin') { // 所有聊天
    return hasContents
  } else if (userRole == 'master') { // 同店用户聊天
    const cmdRes = await cloud.callFunction({
      name: 'userCmd',
      data: {
        cmd: 'getShopUsers', // userId | userOpenId
        userId,
        userOpenId,
        resultType: 'openid'
      }
    })
    const openids = cmdRes.result
    return {
      ...hasContents,
      sessionOpenId: _.in(openids)
    }
  } else { // 仅自己
    return {
      ...hasContents,
      // ...sessionOpenIdOrUserIdCondi(userId, userOpenId)
      userId: userId ? _.eq(userId) : _.exists(true),
      sessionOpenId: userOpenId ? _.eq(userOpenId) : _.exists(true)
    }
  }
}

function getNewMsgCount(chat, user) {
  const readTime = chat.read?.[`${user._id}`]
  chat.newMsgCount = 0
  if (!readTime) {
    for (const msg of chat.contents) {
      if (msg.userId != user._id) chat.newMsgCount += 1
    }
  } else {
    const length = chat.contents.length
    for (let index = length - 1; index >= 0; --index) {
      const ele = chat.contents[index]
      if (ele.time <= readTime) break
      if (ele.userId == user._id) continue
      chat.newMsgCount += 1
    }
  }

  return chat.newMsgCount || 0
}